/*
 * Copyright 2010 Biz-e (info@biz-e.nl)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.biz_e.gwt.baselib.ui.client.windows;

import java.util.Iterator;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Joost A. Bloemsma
 *         TODO Not finished yet!!!
 */
public class MessageBox implements HasWidgets {
    /**
     * Possible icons for the {@link MessageBox}
     */
    public enum Icon {
        /** Icon for the {@link MessageBox} class */
        INFO,
        /** Icon for the {@link MessageBox} class */
        QUESTION,
        /** Icon for the {@link MessageBox} class */
        WARNING,
        /** Icon for the {@link MessageBox} class */
        ERROR,
        /** Icon for the {@link MessageBox} class */
        FATAL
    }

    /**
     * Possible buttons and combinations for the {@link MessageBox}
     */
    public enum MsgBoxButton {
        /** Button for the {@link MessageBox} class */
        OK,
        /** Button for the {@link MessageBox} class */
        YES,
        /** Button for the {@link MessageBox} class */
        NO,
        /** Button for the {@link MessageBox} class */
        CANCEL,
        /** Button for the {@link MessageBox} class */
        ABORT,
        /** Button for the {@link MessageBox} class */
        RETRY,
        /** Button for the {@link MessageBox} class */
        IGNORE,
        /** Button combination for the {@link MessageBox} class */
        OK_CANCEL(new MsgBoxButton[] { MsgBoxButton.OK, MsgBoxButton.CANCEL }),
        /** Button combination for the {@link MessageBox} class */
        YES_NO(new MsgBoxButton[] { MsgBoxButton.YES, MsgBoxButton.NO }),
        /** Button combination for the {@link MessageBox} class */
        YES_NO_CANCEL(new MsgBoxButton[] { MsgBoxButton.YES, MsgBoxButton.NO,
                MsgBoxButton.CANCEL }),
        /** Button combination for the {@link MessageBox} class */
        RETRY_CANCEL(new MsgBoxButton[] { MsgBoxButton.RETRY,
                MsgBoxButton.CANCEL }),
        /** Button combination for the {@link MessageBox} class */
        ABORT_RETRY_IGNORE(new MsgBoxButton[] { MsgBoxButton.ABORT,
                MsgBoxButton.RETRY, MsgBoxButton.IGNORE });

        private MsgBoxButton[] buttons = { this };

        MsgBoxButton() {
            // Intentionally left blank
        }

        MsgBoxButton(MsgBoxButton[] buttons) {
            this.buttons = buttons;
        }

        MsgBoxButton[] getButtonArray() {
            return this.buttons;
        }
    }

    /**
     * Get's notified when a button is clicked
     * 
     */
    public interface MessageBoxHandler {
        /**
         * Get fires when a button is clicked, but before the window is
         * closed.
         * Depending on returnvalue (true or false) the window will be
         * closed
         * 
         * @param clickedButton
         * @return true if window can be closed
         */
        public boolean onClick(MsgBoxButton clickedButton);

        /**
         * Gets triggered just before the window will be closed
         * 
         * @param clickedButton
         */
        public void onClose(MsgBoxButton clickedButton);

    }

    /**
     * TODO: Write type comment
     * 
     * @author Joost A. Bloemsma
     */
    public static class SimpleMessageBoxHandler implements MessageBoxHandler {

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean onClick(MsgBoxButton clickedButton) {
            return true;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onClose(MsgBoxButton clickedButton) {
            // Do nothing...
        }

    }

    private class MButton extends Button {
        private MsgBoxButton button;

        MButton(MsgBoxButton button, ClickHandler handler) {
            super(button.name(), handler);
            this.button = button;
        }

        MsgBoxButton getButton() {
            return this.button;
        }
    }

    private class Handler implements ClickHandler {
        private final MessageBox mBox;

        Handler(MessageBox mBox) {
            super();
            this.mBox = mBox;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onClick(ClickEvent event) {
            mBox.onClick(event);
        }
    }

    private PopupPanel popup;
    private Icon icon = Icon.INFO;
    private String title;
    private Widget widget;
    private MsgBoxButton[] buttons;
    private MsgBoxButton defButton;
    private MessageBoxHandler handler;
    private MsgBoxButton clickedButton = null;
    private final Handler eventHandler;

    /**
     * Constructs a new MessageBox instance
     * 
     * @param message
     */
    public MessageBox(String message) {
        this(null, message);
    }

    /**
     * Constructs a new MessageBox instance
     * 
     * @param title
     * @param message
     */
    public MessageBox(String title, String message) {
        this(title, message, Icon.INFO, MsgBoxButton.OK, null);
    }

    /**
     * Constructs a new MessageBox instance
     * 
     * @param title
     * @param message
     * @param icon
     * @param button
     * @param handler
     */
    public MessageBox(String title, String message, Icon icon,
            MsgBoxButton button, MessageBoxHandler handler) {
        this(title, message, icon, button, button, handler);
    }

    /**
     * Constructs a new MessageBox instance
     * 
     * @param title
     * @param message
     * @param icon
     * @param buttons
     * @param defButton
     * @param handler
     */
    public MessageBox(String title, String message, Icon icon,
            MsgBoxButton buttons, MsgBoxButton defButton,
            MessageBoxHandler handler) {
        this(title, message, icon, buttons.getButtonArray(), defButton, handler);
    }

    /**
     * Constructs a new MessageBox instance
     * 
     * @param title
     * @param message
     * @param icon
     * @param buttons
     * @param defButton
     * @param handler
     */
    public MessageBox(String title, String message, Icon icon,
            MsgBoxButton[] buttons, MsgBoxButton defButton,
            MessageBoxHandler handler) {
        this(title, new HTML(message), icon, buttons, defButton, handler);
    }

    /**
     * Constructs a new MessageBox instance
     * 
     * @param title
     * @param widget
     * @param icon
     * @param buttons
     * @param defButton
     * @param handler
     */
    public MessageBox(String title, Widget widget, Icon icon,
            MsgBoxButton[] buttons, MsgBoxButton defButton,
            MessageBoxHandler handler) {
        super();
        eventHandler = new Handler(this);
        this.title = title;
        this.widget = widget;
        this.icon = icon;
        this.buttons = buttons;
        this.defButton = defButton;

        popup = new PopupPanel(false, true);
        popup.setAnimationEnabled(true);
        popup.setGlassEnabled(true);
        popup.add(getPanel());
        popup.center();
    }

    /**
     * Show the messagebox...
     */
    public void show() {
        popup.show();
    }

    /**
     * ... and close it
     */
    public void close() {
        if (handler != null)
            handler.onClose(clickedButton);
        popup.hide();
    }

    /**
     * @return the message
     */
    public String getMessage() {
        try {
            Label lbl = (Label) this.widget;
            return lbl.getText();
        } catch (ClassCastException cce) {
            return null;
        }
    }

    /**
     * @param message
     *            the message to set
     */
    public void setMessage(String message) {
        this.widget = new Label(message);
    }

    /**
     * @return the icon
     */
    public Icon getIcon() {
        return icon;
    }

    /**
     * @param icon
     *            the icon to set
     */
    public void setIcon(Icon icon) {
        this.icon = icon;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title
     *            the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * Returns the enclosed widget
     * 
     * @return the widget
     */
    public Widget getWidget() {
        return widget;
    }

    /**
     * Sets the enclosed widget
     * 
     * @param widget
     *            the widget to set
     */
    public void setWidget(Widget widget) {
        this.widget = widget;
    }

    /**
     * @return the buttons
     */
    public MsgBoxButton[] getButtons() {
        return buttons;
    }

    /**
     * @param buttons
     *            the buttons to set
     */
    public void setButtons(MsgBoxButton[] buttons) {
        this.buttons = buttons;
    }

    /**
     * @return the defButton
     */
    public MsgBoxButton getDefButton() {
        return defButton;
    }

    /**
     * @param defButton
     *            the defButton to set
     */
    public void setDefButton(MsgBoxButton defButton) {
        this.defButton = defButton;
    }

    /**
     * @return the handler
     */
    public MessageBoxHandler getHandler() {
        return handler;
    }

    /**
     * @param handler
     *            the handler to set
     */
    public void setHandler(MessageBoxHandler handler) {
        this.handler = handler;
    }

    /**
     * @return the clickedButton
     */
    public MsgBoxButton getClickedButton() {
        return clickedButton;
    }

    private Panel getPanel() {
        VerticalPanel vp = new VerticalPanel();

        if (title != null)
            vp.add(new Label(this.title));
        if (widget != null)
            vp.add(widget);

        Widget btnBar = getButtonBar();
        if (btnBar != null)
            vp.add(btnBar);

        return vp;
    }

    private HorizontalPanel getButtonBar() {
        HorizontalPanel hp = new HorizontalPanel();
        for (MsgBoxButton btn : this.buttons) {
            MButton mBtn = new MButton(btn, eventHandler);
            hp.add(mBtn);
        }
        return hp;
    }

    /**
     * @param event
     */
    private void onClick(ClickEvent event) {
        clickedButton = ((MButton) event.getSource()).getButton();
        if (handler != null) {
            if (!handler.onClick(clickedButton)) {
                clickedButton = null;
                return;
            }
        }
        this.close();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void add(Widget w) {
        // TODO Auto-generated method stub

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void clear() {
        // TODO Auto-generated method stub

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Iterator<Widget> iterator() {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean remove(Widget w) {
        // TODO Auto-generated method stub
        return false;
    }

}
